<?php
/*=============================================================================
|| ##################################################################
||	phpFoX Konsort
|| ##################################################################
||
||	Copyright		: (C) 2005-2007 PHPFOX Limited a Reality Fox Creation
||	Contact			: info@phpfox.com
||
||	- phpFoX and all of its source code and files are protected by Copyright Laws.
||
||	- The license for phpFoX permits you to install this software on a single domain (.com, .org, .net, etc.).
||
||	- You may also not remove this copyright screen which shows the copyright information and credits for phpFoX (RealityFOX Creations).
||
||	- phpFoX Konsort is NOT a FREE software - http://www.phpfox.com/license/
||
|| ##################################################################
=============================================================================*/

/* $File: ./include/classes/Text.class.php, $Author:  $ */

if ( file_exists(App::getParam('path') . "include/functions/Text.functions.php") )
{
	require_once(App::getParam('path') . "include/functions/Text.functions.php");
}

/**
 * This class prepare text messages
 * @package core
 */
class Text extends Object
{
    function Text()
    {
    }

    /** Parse bbcode and smile
     * @todo Parse bbcode and smile
     * @param string $sTxt
     * @return string (parsed text)
     * @access public
     */
    function parseText($sTxt, $bDontAllowHtml = false, $bInUserProfilePage = false, $bClearUserEndLine=false)
    {
    	if($bClearUserEndLine)
    	{
    		$sTxt = str_replace("\r\n", ' ', $sTxt);
    		$sTxt = str_replace("\r", ' ', $sTxt);
    		$sTxt = str_replace("\n", ' ', $sTxt);
    		return $sTxt;
    	}
    	$sTxt = str_replace("<br>", "[BR]", $sTxt);
		$sTxt = $this->cleanHtml($sTxt, $bDontAllowHtml, $bInUserProfilePage);
		$sTxt = $this->_code2Html($sTxt);
        $sTxt = $this->_code2Quote($sTxt);
		$sTxt = $this->_code2QuoteLong($sTxt);
        $sTxt = $this->_parseSmile($sTxt);
        $sTxt = $this->_splitString($sTxt);
        $sTxt = $this->preParseText($sTxt);

        $sTxt = str_replace("[BR]","<br />", $sTxt);
    	$sTxt = str_replace("[br]","<br />", $sTxt);		

		$sHash =  App::getParam('Mod_Site.bbcode.hash');
		$sTxt = str_replace("PHPFOX[". $sHash ."][class]", 'class', $sTxt);
		
        return $sTxt;
    }
    
    function replaceBbcode($sText)
    {
    	$sHash =  App::getParam('Mod_Site.bbcode.hash');
    	$sText = preg_replace("/\<div PHPFOX\[" . $sHash . "\]\[class\]=\"forum-q\"\>(.*?)\<\/div\>/ise", "'[quote]' . stripslashes('$1') . '[/quote]'", $sText);
    	return $sText;
    }
    
    function preParseChat($sText)
    {
    	$sText = trim($sText);
    	$sText = str_replace("&nbsp;", "", $sText);
    	$sText = str_replace(array("\n", "\t", "\r"), "", $sText);
    	$sText = strip_tags($sText, App::getParam('chat_allowed_html') . "<img>");    	
		
    	return $sText;
    }

    function parsePostChat($sText)
    {
		$sText = $this->_parseSmile($sText);
    	$sText = $this->preParseText($sText);
    	$sText = strip_tags($sText, App::getParam('chat_allowed_html'));
    	$sText = preg_replace("/\[PHPFOX_IMAGE=". App::getParam('Mod_Site.bbcode.hash') ."\](.*?)\[\/PHPFOX_IMAGE\]/ise", "'<img'.\$this->_removeEvilAttributes('$1').'>'", $sText);
		
    	return $sText;
    }

    function _createHighlight($sStr, $sHighLight, $sLink)
    {
    	$sStr = eregi_replace(" ". $sHighLight ." ", ' <a href="'. $sLink .'">'. $sHighLight .'</a> ', $sStr);
		return $sStr;
    }

    function rmSpecialChars($sTxt)
    {
    	$sTxt = str_replace("\"", "&quot;", $sTxt);
        $sTxt = str_replace("'",  "&#39;", $sTxt);
        $sTxt = str_replace(">",  "&gt;", $sTxt);
        $sTxt = str_replace("<",  "&lt;", $sTxt);
        return $sTxt;
    }

    function _parseMember($sUser, $iType)
    {
    	if (App::getParam('bbcode_query_user')) 
   		{
   			$oDb =& Database::get();   		
			$aRow = $oDb->getRow("SELECT user FROM " . App::getT('user') . " WHERE user = '" . $oDb->escape($sUser) . "'");
			if (!isset($aRow['user']))
			{
				return '';
			}
			$sUser = $aRow['user'];
   		}    	
    
        $sUserProfile = App::makeUrl('public.user', array('name' => $sUser));

        if(is_readable(App::getParam('user.pic.path') . $sUser.'_75.jpg'))
        {
            $sUserPic = App::getParam('user.pic.url') . $sUser.'_75.jpg';
		}
        else
        {
            $sUserPic = App::getParam('url').'design/pic/noimage.jpg';
		}

        $sText = '';

		switch ($iType)
        {
        	case 1:
            $sText = '<a href=\''.$sUserProfile.'\'>'.$sUser.'</a>';
			break;
			default:
			$sText = '<a href=\''.$sUserProfile.'\'>';
			$sText .= "<img src=\"".$sUserPic."\" title=\"".$sUser."\" alt=\"".$sUser."\" /></a> ";
			break;
		}

        return $sText;
    }

    function _html2Style($sTxt)
    {
        $sTxt = str_replace("[BR]","",$sTxt);
    	$sTxt = '<style type="text/css">'. strip_tags($sTxt) .'</style>';
    	return $sTxt;
    }

    function _parseMail($sStr)
    {
		if ( function_exists('phpfoxText_parseMail') )
		{
			$sStr = phpfoxText_parseMail($sStr);
		}

    	return '<a href="mailto:'.$sStr.'">'.$sStr.'</a>';
    }

    function _parseImage($src,$width,$height)
    {
		if ( function_exists('phpfoxText_parseImage') )
		{
			$src = phpfoxText_parseImage($src);
		}

		return '<img src='. $src .' width='. $width .' height='. $height .' alt="" />';
    }

    function _parseImage2($sImg)
    {
		if ( function_exists('phpfoxText_parseImage2') )
		{
			$sImg = phpfoxText_parseImage2($sImg);
		}

    	return '<img src="'.$sImg .'" alt="" /> ';
    }

    function js_clean($sStr)
    {
    	$sStr = strip_tags($sStr);
    	$sStr = $this->_removeEvilAttributes($sStr);
    	return $sStr;
    }

    function _code2Quote($sStr)
    {

        $aNew = array();
    	$aNew = explode("quote=",$sStr);

    	$iTotal = count($aNew);

    	if($iTotal != 1)
    	{
        	for ($i = 0; $i < $iTotal; $i++)
    	       $sStr = preg_replace("/\[quote=(.*?)\](.*?)\[\/quote\]/ise","''.stripslashes(\$this->_forum2Code('$1','$2','')).''",$sStr);
    	}

        return $sStr;
    }

    function _code2QuoteLong($sStr)
    {
        $aNew = array();
    	$aNew = explode("quote",$sStr);
    	$iTotal = count($aNew);

    	if ($iTotal != 1)
    	{
    		for ($i = 0; $i < $iTotal; $i++)
    		{
    			$sStr = preg_replace("/\[quote\](.*?)\[\/quote\]/ise","''.stripslashes(\$this->_forum2Code('','$1','1')).''",$sStr);
    		}
    	}

    	return $sStr;
    }

    function _parseTable($i,$sStr)
    {
    	$sStr = str_replace("[BR]","",$sStr);

    	if ($i > 100) $i = 100;

    	$sStr = '<table style="width:'.$i.'%"><tr>'.$sStr.'</tr></table>';
    	$sStr = preg_replace("/\[td\](.*?)\[\/td\]/si","<td>\\1</td>",$sStr);
    	return $sStr;
    }

    function _forum2Code($sUser,$sTxt,$sType)
    {
        $sUser = str_replace("\"","",$sUser);

    	$sTxt = $this->_code2Quote($sTxt);

    	$sSay = App::format('Mod_Comments.user_wrote', $sUser) . ":";
    	if ($sType == 1)
    	{
    	   $sSay = "". App::format('Mod_Comments.quote') .":";
    	}
    	$sNewTxt = '<table style="width:95%;" cellpadding="0" cellspacing="0">
    	<tr>
    		<td style="width:2%;"><br /></td><td style="width:98%;font-size:8pt;" class="color">
    			<b>'.$sSay.'</b>
    			<div PHPFOX['. App::getParam('Mod_Site.bbcode.hash') .'][class]="forum-q">

    			'.$sTxt.'

    			</div>
    		</td>
    	</tr>
    	</table>';

    	return $sNewTxt;
    }

    function _parseSmile($sStr)
    {    	
    	static $aEmo1;
        static $aEmo2;

		if ( !$aEmo1 )
		{
			$aEmo1 = array();
        	$dir = opendir(App::getParam('smile.path'));
    		while ($file = readdir($dir))
    		{
    			if (ereg("jpg",$file) || ereg("gif",$file))
    			{
    				$name = str_replace(".jpg","",$file);
    				$name = str_replace(".gif","",$name);
					$aEmo1[] = $name;
    			}
    		}
    	}

		if ( !$aEmo2 )
		{
			$aEmo2 = array();
        	$dir = opendir(App::getParam('smile.path').'emo/');
    		while ($file = readdir($dir))
    		{
    			if (ereg("jpg",$file) || ereg("gif",$file))
    			{
    				$name = str_replace(".jpg","",$file);
    				$name = str_replace(".gif","",$name);
					$aEmo2[] = $name;
    			}
    		}
    	}

    	$bProtectImage = (defined('PHPFOX_PROTECT_IMG') ? true : false);
    	$sHash = App::getParam('Mod_Site.bbcode.hash');

    	foreach($aEmo1 as $name1)
    	{
    		 $sStr = str_replace(":".$name1.":","<". ($bProtectImage ? 'img phpfox="image-protect"' : 'img') ." src=\"".App::getParam('smile.url').$name1.".gif\" alt=\"\" style=\"vertical-align:middle;\" /> ",$sStr);
    	}

    	foreach($aEmo2 as $name2)
    	{
    		$sStr = str_replace(":".$name2.":","<". ($bProtectImage ? 'img phpfox="image-protect"' : 'img') ." src=\"".App::getParam('smile.url')."emo/".$name2.".gif\" alt=\"\" style=\"vertical-align:middle;\" /> ",$sStr);
    	}
    	
    	if ( eregi('image-protect', $sStr) )
    	{
    		if ( $bProtectImage )
    		{
    			$sStr = preg_replace("/<img(.*?)\>/i", "[PHPFOX_IMAGE=". $sHash ."]$1[/PHPFOX_IMAGE]", $sStr);
    		}
    		$sStr = str_replace('phpfox="image-protect"', '', $sStr);
    	}

    	return $sStr;
    }

    function _parseSource($sStr)
    {
    	$sNew = '
    	<table style="width:100%;" cellpadding="0" cellspacing="0">
    		<tr>
    		<td style="width:2%;"><br /></td><td style="width:98%;font-size:8pt;" class="color">
    			<b>Code:</b>
    			<div style="padding:4px;">
    			<div PHPFOX['. App::getParam('Mod_Site.bbcode.hash') .'][class]="forum-q" style="padding:10px;">

    			'.$sStr.'

    			</div>
    			</div>
    			</td>
    		</tr>
    	</table>';

    	return $sNew;
    }


    function _code2Html($sStr)
    {
        global $_CONF;

		if ( function_exists('phpfoxText_code2Html') )
		{
			$sStr = phpfoxText_code2Html($sStr);
		}

    	if ( App::getParam('html_add_br') )
    	{
			$sStr = str_replace("\n", "[BR]", $sStr);
		}

    	if (App::getSetting('allow_html') == '1')
    	{
    	   $sStr = preg_replace("/\<style(.*?)\>(.*?)\<\/style\>/ise","''.\$this->_html2Style('$2').''",$sStr);
    	}

        $sStr = preg_replace("/\[table=(.*?)\](.*?)\[\/table\]/ise","''.\$this->_parseTable('$1','$2').''",$sStr);
    	//$sStr = str_replace("[BR]","<br />",$sStr);
    	//$sStr = str_replace("[br]","<br />",$sStr);
    	$sStr = preg_replace("/\[img\](.*?)\[\/img\]/ise","''.\$this->_parseImage2(\$this->js_clean('$1')).''",$sStr);
    	$sStr = preg_replace("/\[img src=(.*?) width=(.*?) height=(.*?)\]/ise","''.\$this->_parseImage(\$this->js_clean('$1'),\$this->js_clean('$2'),\$this->js_clean('$3')).''",$sStr);
    	$sStr = preg_replace("/\[center\](.*?)\[\/center\]/ise","'<div style=\"text-align:center;\">'.stripslashes('$1').'</div>'",$sStr);
    	$sStr = preg_replace("/\[i\](.*?)\[\/i\]/si","<i>\\1</i>",$sStr);
    	$sStr = preg_replace("/\[b\](.*?)\[\/b\]/si","<b>\\1</b>",$sStr);
    	$sStr = preg_replace("/\[u\](.*?)\[\/u\]/si","<u>\\1</u>",$sStr);
    	$sStr = preg_replace("/\[hr\](.*?)\[\/hr\]/si","<hr>\\1</hr>",$sStr);
    	$sStr = preg_replace("/\[hr\]/si","<hr></hr>",$sStr);
    	$sStr = preg_replace("/\[profile\](.+?)\[\/profile\]/ise","''.stripslashes(\$this->_parseMember('$1',2)).''",$sStr);
    	$sStr = preg_replace("/\[user\](.+?)\[\/user\]/ise","''.stripslashes(\$this->_parseMember('$1',1)).''",$sStr);
    	$sStr = preg_replace("/\[color=(.*?)\](.*?)\[\/color\]/ise","'[color='.stripslashes(str_replace('\"','','$1')).'] $2[/color]'",$sStr);
    	$sStr = preg_replace("/\[color=(.*?)\](.*?)\[\/color\]/ise","'<span style=\"color:'.stripslashes('$1').';\">'.stripslashes('$2').'</span>'",$sStr);
    	$sStr = preg_replace("/\[size=(.*?)\](.*?)\[\/size\]/ise","'[size='.stripslashes(str_replace('\"','','$1')).'] $2[/size]'",$sStr);
    	$sStr = preg_replace("/\[size=(.*?)\](.*?)\[\/size\]/ise","'<font size=\"'.stripslashes(str_replace('\"','','$1')).'\">'.stripslashes('$2').'</font>'",$sStr);
    	$sStr = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/ise","'[font='.stripslashes(str_replace('\"','','$1')).'] $2[/font]'",$sStr);
    	$sStr = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/ise","'<font face=\"'.stripslashes(str_replace('\"','','$1')).'\">'.stripslashes('$2').'</font>'",$sStr);
    	$sStr = preg_replace("/\[link=(.*?)\](.*?)\[\/link\]/si","<a href=$1 onclick=\"window.open(this.href,'_blank');return false;\">\\2</a>",$sStr);
    	$sStr = preg_replace("/\[link=(.*?)\](.*?)\[\/link\]/si","<a href=\"$1\" onclick=\"window.open(this.href,'_blank');return false;\">\\2</a>",$sStr);
    	$sStr = preg_replace("/\[a=(.*?)\](.*?)\[\/a\]/ise","'<a href='.\$this->js_clean('$1').'>$2</a>'",$sStr);
    	$sStr = preg_replace("/\[align=(.*?)\](.*?)\[\/align\]/ise","'<div style=\"width:100%;text-align:'.stripslashes(str_replace('\"','','$1')).'\">\\2</div>'",$sStr);
    	$sStr = preg_replace("/\[ul\](.*?)\[\/ul\]/si","<ul>\\1</ul>",$sStr);
    	$sStr = preg_replace("/\[ol\](.*?)\[\/ol\]/si","<ol>\\1</ol>",$sStr);
    	$sStr = preg_replace("/\[li\](.*?)\[\/li\]/si","<li>\\1</li>",$sStr);
    	$sStr = preg_replace("/\[em\](.*?)\[\/em\]/si","<em>\\1</em>",$sStr);
    	$sStr = preg_replace("/\[listing\](.*?)\[\/listing\]/si",'<div style="padding:8px;"><b>'. App::format('Mod_Listing.listing_id') .':</b> \\1 - [ <a href="'. App::makeUrl('public.listing.view', array('id' => '$1')) .'">View Listing</a> ]</div>',$sStr);
    	$sStr = preg_replace("/\[strong\](.*?)\[\/strong\]/si","<strong>\\1</strong>",$sStr);
    	$sStr = preg_replace("/\[email\](.*?)\[\/email\]/ise","''.\$this->_parseMail('$1').''",$sStr);
    	$sStr = preg_replace("/\[source\](.*?)\[\/source\]/ise","''.\$this->_parseSource('$1').''",$sStr);
    	$sStr = preg_replace('/<(.*?)>/ise', "'<'.\$this->_removeEvilAttributes('\\1').'>'", $sStr);
    	$sStr = preg_replace('/-moz-binding/i', '', $sStr);
    	$sStr = stripslashes($sStr);

    	return $sStr;
    }

    function _stripEvilTags($sStr, $sAllow, $bDontAllowHtml = false)
    {
        if (!App::getSetting('allow_html') || $bDontAllowHtml)
        {
            $sAllowedTags = "<br/><br /><br><font><span><p><strong><u><p><blockquote><a><img><font><em><li><ol><ul>".$sAllow."";
            $sStr = strip_tags($sStr, $sAllowedTags);
        }
        return preg_replace('/<(.*?)>/ise', "'<'.\$this->_removeEvilAttributes('\\1').'>'", $sStr);
    }

    function cleanHtml($sTxt, $bDontAllow = false, $bInUserProfilePage = false)
    {
        $sAllowedTags = '<p><br><br />';
        if (App::getSetting('allow_html') && !$bDontAllow)
        {
        	// $sTxt = str_replace("&lt;","<",$sTxt);
			// $sTxt = str_replace("&gt;",">",$sTxt);
			$sTxt = preg_replace("/\&lt;(.*?)\&gt;/si","<\\1>",$sTxt);
			$sTxt = str_replace("&quot;",'"',$sTxt);
			$sAllowedTags .= '<p><strong><em><u><ul><li><br/><font><ol><img><div><span>';
			$sAllowedTags .= '<blockquote><strike><sub><sup><h1><h2><h3><h4><h5><h6>';
           	$sAllowedTags .= '<a><b><i><hr><tt><s><center><big><abbr><pre><small><object><embed><param>';
        }
        if ($bInUserProfilePage)
        {
            $sAllowedTags .= '<style>';
        }
        $sTxt = strip_tags($sTxt, $sAllowedTags);
        $sTxt = preg_replace('/<(.*?)>/ise', "'<'.\$this->_removeEvilAttributes('\\1',\$bInUserProfilePage).'>'", $sTxt);
		// $sTxt = str_replace("[BR]","<br />", $sTxt);
        return $sTxt;
    }

    function _removeEvilAttributes($sTxt, $bInUserProfilePage = false)
    {
    	$sTxt = str_replace("xhref","href",$sTxt);
    	$sTxt = str_replace("xsrc","src",$sTxt);
        $sTxt = strip_tags($sTxt);
        $sTxt = str_replace('[BR]', '', $sTxt);
      	$sTxt = stripslashes($sTxt);      	
      	$aEvents = array
      	(
      	    'onActivate',
            'onAfterPrint',
            'onBeforePrint',
            'onAfterUpdate',
            'onBeforeUpdate',
            'onErrorUpdate',
            'onAbort',
            'onBeforeDeactivate',
            'onDeactivate',
            'onBeforeCopy',
            'onBeforeCut',
            'onBeforeEditFocus',
            'onBeforePaste',
            'onBeforeUnload',
            'onBlur',
            'onBounce',
            'onChange',
            'onClick',
            'onControlSelect',
            'onCopy',
            'onCut',
            'onDblClick',
            'onDrag',
            'onDragEnter',
            'onDragLeave',
            'onDragOver',
            'onDragStart',
            'onDrop',
            'onFilterChange',
            'onDragDrop',
            'onError',
            'onFilterChange',
            'onFinish',
            'onFocus',
            'onHelp',
            'onKeyDown',
            'onKeyPress',
            'onKeyUp',
            'onLoad',
            'OnLoseCapture',
            'onMouseDown',
            'onMouseEnter',
            'onMouseLeave',
            'onMouseMove',
            'onMouseOut',
            'onMouseOver',
            'onMouseUp',
            'onMove',
            'onPaste',
            'onPropertyChange',
            'onReadyStateChange',
            'onReset',
            'onResize',
            'onResizeEnd',
            'onResizeStart',
            'onScroll',
            'onSelectStart',
            'onSelect',
            'onSelectionChange',
            'onStart',
            'onStop',
            'onSubmit',
            'onUnload',
            'class',
            'javascript'
      	);

      	if ( !App::getParam('html_allow_style') )
      	{
      		$aEvents[] = 'style';
      	}

        foreach ($aEvents as $sRemove)
        {
            $sTxt = preg_replace('#'.$sRemove.'=#i', 'title=', $sTxt);
        }
        
        $sTxt = preg_replace('#javascript:#i', 'title=', $sTxt);

   	    $aEvilCss = array
   	    (
			'position',
			'top',
			'left',
			'background',
			'background-image',
			'background-color',
			'width',
			'height'
        );

        foreach($aEvilCss as $sCss)
        {
       		$sTxt = preg_replace('/'. $sCss .':(.*?)/i', 'replaced:', $sTxt);
       	}

        return $sTxt;
    }

    function preParseText($sTxt)
    {
        $oBanService = &App::getModuleService('Site', 'Ban');
        /* @var $oBanService PhpFox_Mod_Site_ServiceBan */
        return $oBanService->parseStringForBadwords($sTxt);
    }

    function _splitString($sString, $iCount = 75, $sSplitString=' ')
    {
    	$text = $sString;
   		$new_text = '';
   		$text_1 = explode('>',$text);
   		$sizeof = sizeof($text_1);
   		for ($i=0; $i<$sizeof; ++$i) {
        	$text_2 = explode('<',$text_1[$i]);
       		if (!empty($text_2[0])) {
           	
       				$new_text .= preg_replace('#([^\n\r .]{'. $iCount .'})#iu', '\\1  ', $text_2[0]);
       		}
       		if (!empty($text_2[1])) {
           		$new_text .= '<' . $text_2[1] . '>';
       		}
   		}
   		return $new_text;
    }

    function utf8_subst($str, $from, $len)
    {
        return preg_replace('#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$from.'}'.
                       '((?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$len.'}).*#s',
                       '$1',$str);
    }

    function ShortenText($text,$count,$allow = '')
    {
        $sAllowedTags = '<p><strong><em><u><ul><li><br/><br><br /><font><ol><img><div><span>';
        if (App::getSetting('allow_html'))
        {
            $sAllowedTags .= '<blockquote><strike><sub><sup><h1><h2><h3><h4><h5><h6>';
            $sAllowedTags .= '<a><b><i><hr><tt><s><center><big><abbr><pre><small>';
        }
    	$i = str_word_count($text);
        $bLong = false;
    	$text = strip_tags($text,$sAllowedTags);
    	$text = $this->_code2Quote($this->_code2QuoteLong($this->_code2Html($text)));

    	$chars = $count;
        $text = $text." ";
        $text = substr($text,0,$chars);

    	return $text;
    }

    function foxEscape($sTxt)
    {
        $sTxt = preg_replace("/\[code\](.*?)\[\/code\]/ise","'[source]'.htmlspecialchars('$1', ENT_QUOTES).'[/source]'",$sTxt);

    	$sTxt = str_replace(chr(145), chr(39), $sTxt);
    	$sTxt = str_replace(chr(146), chr(39), $sTxt);
    	$sTxt = str_replace("'", "&#39;", $sTxt);
    	$sTxt = str_replace(chr(147), chr(34), $sTxt);
    	$sTxt = str_replace(chr(148), chr(34), $sTxt);
    	$sTxt = str_replace(chr(13), " ", $sTxt);

    	if (App::getSetting('allow_html') != '1')
    	   return strip_tags($sTxt);
    	else
    	   return $sTxt;
    }
    
    function utf8ToUnicode($str) 
    {        
        $unicode = array();        
        $values = array();
        $lookingFor = 1;
        
        for ($i = 0; $i < strlen( $str ); $i++ ) 
        {
            $thisValue = ord( $str[ $i ] );
            if ( $thisValue < 128 )
            {
            	$unicode[] = $thisValue;
            }
            else 
            {            
                if ( count( $values ) == 0 ) $lookingFor = ( $thisValue < 224 ) ? 2 : 3;
                
                $values[] = $thisValue;
                
                if ( count( $values ) == $lookingFor ) {
            
                    $number = ( $lookingFor == 3 ) ?
                        ( ( $values[0] % 16 ) * 4096 ) + ( ( $values[1] % 64 ) * 64 ) + ( $values[2] % 64 ):
                    	( ( $values[0] % 32 ) * 64 ) + ( $values[1] % 64 );
                        
                    $unicode[] = $number;
                    $values = array();
                    $lookingFor = 1;
            
                }            
            }            
        }

        return $this->_unicodeToEntitiesPreservingAscii($unicode);    
    }
    
    function _unicodeToEntitiesPreservingAscii($unicode) 
    {    
        $entities = '';
        foreach( $unicode as $value ) 
        {       
            $entities .= ( $value > 127 ) ? '&#' . $value . ';' : chr( $value );            
        }
        return $entities;        
    }
}
?>